package com.zmn.plat.business.impl.product.tariff.item;

import com.alibaba.fastjson.JSON;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.zmn.common.constant.GlobalConsts;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.plat.business.interfaces.brand.ratio.BrandRatioBService;
import com.zmn.plat.business.interfaces.channel.ChannelCityPriceRatioBService;
import com.zmn.plat.business.interfaces.channel.ChannelServiceCategoryBService;
import com.zmn.plat.business.interfaces.product.tariff.item.ProductServiceItemPriceBService;
import com.zmn.plat.common.dictionary.BaseCityPriceTypeEnum;
import com.zmn.plat.common.dictionary.ChannelCityRatioTypeEnum;
import com.zmn.plat.common.dto.brand.factor.BrandFactorDRO;
import com.zmn.plat.common.dto.product.item.ItemPriceDRO;
import com.zmn.plat.common.exception.PlatException;
import com.zmn.plat.common.util.CityPriceUtil;
import com.zmn.plat.manager.dictionary.ProductDict;
import com.zmn.plat.model.dto.service.ItemPriceCalDTO;
import com.zmn.plat.model.dto.service.ItemPriceDTO;
import com.zmn.plat.model.entity.base.difficult.ratio.DifficultRatio;
import com.zmn.plat.model.entity.channel.ChannelCityPriceRatio;
import com.zmn.plat.model.entity.channel.ChannelCityPriceRatioQuery;
import com.zmn.plat.model.entity.channel.brand.ratio.ChannelBrandAllLevelRatioQuery;
import com.zmn.plat.model.entity.product.ServProduct;
import com.zmn.plat.model.vo.channel.brand.ratio.ChannelBrandRatioAllLevelVo;
import com.zmn.plat.model.vo.product.tariff.item.BaseTariffGroupItemPriceVo;
import com.zmn.plat.services.interfaces.base.difficult.ratio.DifficultRatioService;
import com.zmn.plat.services.interfaces.channel.ChannelCityPriceRatioService;
import com.zmn.plat.services.interfaces.channel.brand.ratio.ChannelBrandRatioService;
import com.zmn.plat.services.interfaces.product.ServProductService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

/**
 * @author tanbiao
 * @description
 * @modifier
 * @since 2020/3/19 17:48
 **/
@Service
public class ProductServiceItemPriceBServiceImpl implements ProductServiceItemPriceBService {
    private Logger logger = LoggerFactory.getLogger(ProductServiceItemPriceBServiceImpl.class);
    // 默认系数
    private final static Float RESULT_RATIO = 1.0F;
    // 系数不存在缓存值给定值
    private final static Float CACHE_DEFAULT_RATIO = -1.0F;
    @Resource
    ChannelCityPriceRatioService channelCityPriceRatioService;
    @Resource
    BrandRatioBService brandRatioBService;
    @Resource
    ChannelCityPriceRatioBService channelCityPriceRatioBService;
    @Resource
    ServProductService servProductService;
    @Resource
    ChannelBrandRatioService channelBrandRatioService;
    @Resource
    ChannelServiceCategoryBService channelServiceCategoryBService;
    @Resource
    DifficultRatioService difficultRatioService;

    // 考虑难度系数的情况下价格的最小值
    private static final int MIN_PRICE_FEN = 15000;
    // 普通故障类型id
    private static final int FAULT_CATEG_ID_NORMAL = 1000;

    private static final List<Integer> DIFFICULT_LIST = Arrays.asList(1000, 1002);

    private static final String SPCEIL_ITEM_NAME = "调试/紧固等";

    // 本缓存时间
    private static final int MAX_CACHE_EXP = 300;
    // 渠道折扣本地缓存
    private Cache<String, Float> channelDiscountCache = CacheBuilder.newBuilder().expireAfterWrite(MAX_CACHE_EXP, TimeUnit.SECONDS).build();
    // 城市系数本地缓存
    private Cache<String, Float> cityCache = CacheBuilder.newBuilder().expireAfterWrite(MAX_CACHE_EXP, TimeUnit.SECONDS).build();
    // 品牌系数本地缓存
    private Cache<String, Float> brandCache = CacheBuilder.newBuilder().expireAfterWrite(MAX_CACHE_EXP, TimeUnit.SECONDS).build();
    // 难度系数本地缓存
    private Cache<Integer, DifficultRatio> difficultCache = CacheBuilder.newBuilder().expireAfterWrite(MAX_CACHE_EXP, TimeUnit.SECONDS).build();

    @Override
    public Float getChannelDiscount(Integer channelId, Integer bizType, Integer priceType) {
        try {
            String key = channelId + "_" + bizType + "_" + priceType;
            return channelDiscountCache.get(key, () -> getChannelDiscountNoCache(channelId, bizType, priceType));
        } catch (Exception e) {
            logger.error("缓存方式获取渠道折扣失败", e);

            throw new PlatException("缓存方式获取渠道折扣失败");
        }

    }

    @Override
    public Float getCityRatio(Integer channelId, Integer cityId, Integer productId, Integer bizType, Integer cityPriceType) {
        try {
            String key = channelId + "_" + cityId + "_" + productId + "_" + bizType + "_" + cityPriceType;
            return cityCache.get(key, () -> getCityRatioNoCache(channelId, cityId, productId, bizType, cityPriceType));
        } catch (Exception e) {
            logger.error("缓存方式获取城市系数失败", e);

            throw new PlatException("缓存方式获取城市系数失败");
        }
    }

    @Override
    public Float getBrandRatio(Integer channelId, Integer brandId, Integer productId, Integer bizType, Integer brandPriceType) {
        try {
            String key = channelId + "_" + brandId + "_" + productId + "_" + bizType + "_" + brandPriceType;
            return brandCache.get(key, () -> getBrandRatioNoCache(channelId, brandId, productId, bizType, brandPriceType));
        } catch (Exception e) {
            logger.error("缓存方式获取城市系数失败", e);

            throw new PlatException("缓存方式获取城市系数失败");
        }
    }

    @Override
    public void getTotalPrice(BaseTariffGroupItemPriceVo priceVo, ItemPriceDRO itemPriceDRO) {
        logger.info("getTotalPrice 参数为:,vo={},itemPriceDRO={}", JSON.toJSONString(priceVo), JSON.toJSONString(itemPriceDRO));
        Integer number = itemPriceDRO.getNumber();
        Integer price = priceVo.getPrice();
        if (!NumberUtil.isPositiveInteger(price) || !NumberUtil.isPositiveInteger(number)) {
            logger.error("getTotalPrice原始价格或者数量不合法，无法计算阶梯价，price={}，number={}", price, number);
            itemPriceDRO.setFianlMessage("原始价格或者数量不合法");
            return;
        }

        // 传入的item不是阶梯价，那么返回原始价格*数量
        BigDecimal orgPriceOne = new BigDecimal(price);
        BigDecimal numberB = new BigDecimal(number);
        BigDecimal orgPriceTotal = orgPriceOne.multiply(numberB);
        Integer intPriceTotal = orgPriceTotal.setScale(0, BigDecimal.ROUND_DOWN)
                .divide(new BigDecimal(ProductDict.HUNDRED), 2, RoundingMode.HALF_UP).setScale(0, RoundingMode.HALF_UP).intValue()*ProductDict.HUNDRED;
        if (Objects.isNull(priceVo.getPriceSplitType()) || Objects.equals(priceVo.getPriceSplitType(), GlobalConsts.NO)) {
            logger.info("getTotalPrice 不是阶梯价，直接返回价格*数量，itemId={}", priceVo.getItemId());
            itemPriceDRO.setTotalPrice(intPriceTotal);
            itemPriceDRO.setFianlMessage("不是阶梯价定价方式");
            return;
        }

        // 计算阶梯价,材料费=价格*材料费百分比，工艺费=价格-材料费,阶梯的优惠在于对工艺费的优惠
        // 1.数量小于阶梯，价格不变
        Integer numberStep = priceVo.getNumberStep();
        if (!NumberUtil.isPositiveInteger(numberStep)) {
            logger.error("getTotalPrice numberStep不合法，无法计算阶梯价，numberStep={}", numberStep);
            itemPriceDRO.setTotalPrice(intPriceTotal);
            itemPriceDRO.setFianlMessage("itemId对应的项目numberStep不合法");
            return;
        }
        // 阶梯价参数检查
        Integer materialFee = priceVo.getMaterialFee();
        if (!NumberUtil.isPositiveInteger(materialFee)) {
            logger.error("getTotalPrice 材料费不合法无法计算阶梯价", materialFee);
            itemPriceDRO.setTotalPrice(intPriceTotal);
            itemPriceDRO.setFianlMessage("itemId对应的项目材料费不合法");
            return;
        }
        // 材料费，工艺费
        BigDecimal materialFeePercent = new BigDecimal(materialFee).divide(new BigDecimal(ProductDict.HUNDRED)).setScale(2, BigDecimal.ROUND_HALF_UP);
        BigDecimal artFeePercent = BigDecimal.ONE.subtract(materialFeePercent);
        if (number < numberStep) {
            logger.info("数量没有达到阶梯值，总价=单价*数量");
            itemPriceDRO.setTotalPrice(intPriceTotal);
            itemPriceDRO.setTotalMaterialPrice(orgPriceTotal.multiply(materialFeePercent).intValue() / 100 * 100);
            itemPriceDRO.setTotalArtPrice(intPriceTotal - itemPriceDRO.getTotalMaterialPrice());
            itemPriceDRO.setFianlMessage("数量没有达到阶梯值限制");
            return;
        }

        // 2.大于等于的情况下才计算阶梯
        Integer baseDiscount = priceVo.getBaseDiscount();
        Integer numberStepDown = priceVo.getNumberStepDown();
        if (!NumberUtil.isPositiveInteger(baseDiscount) || !NumberUtil.isPositiveInteger(numberStepDown)) {
            logger.error("getTotalPrice 底折或者阶梯值降幅不合法，无法计算阶梯价，materialFee={}，baseDiscount={},numberStepDown={}", materialFee, baseDiscount, numberStepDown);
            itemPriceDRO.setTotalPrice(intPriceTotal);
            itemPriceDRO.setFianlMessage("itemId对应的数据底折或者阶梯值降幅不合法");
            return;
        }
        //底折，阶梯值降幅
        BigDecimal baseDiscountPercent = new BigDecimal(baseDiscount).divide(new BigDecimal(ProductDict.HUNDRED)).setScale(2, BigDecimal.ROUND_HALF_UP);
        BigDecimal numberStepDownPercent = new BigDecimal(numberStepDown).divide(new BigDecimal(ProductDict.HUNDRED)).setScale(2, BigDecimal.ROUND_HALF_UP);
        // 比较（1-数量/数量阶梯值*阶梯降幅）和底折的大小，比底折小，那么取底折
        BigDecimal mub = numberB.divide(new BigDecimal(numberStep), 2, BigDecimal.ROUND_HALF_UP).setScale(0, BigDecimal.ROUND_DOWN);
        BigDecimal result = BigDecimal.ONE.subtract(mub.multiply(numberStepDownPercent));
        if (result.compareTo(baseDiscountPercent) < 0) {
            result = baseDiscountPercent;
        }
        // 单价 = 材料费+工艺费
        // 材料费保持不变
        BigDecimal materialFeeB = orgPriceOne.multiply(materialFeePercent);
        // 工艺费需要打折
        BigDecimal artFeeDiscountPercent = artFeePercent.multiply(result);
        BigDecimal artFeeB = orgPriceOne.multiply(artFeeDiscountPercent);
        // 最终单价
        BigDecimal oneFinalPrice = materialFeeB.add(artFeeB);
        BigDecimal total = oneFinalPrice.multiply(numberB).setScale(0, BigDecimal.ROUND_HALF_UP);
        // 总价需要四舍五入保留整数
        total = total.divide(new BigDecimal(ProductDict.HUNDRED), 2, RoundingMode.HALF_UP).setScale(0, RoundingMode.HALF_UP);
        Integer totalPrice = total.intValue() * ProductDict.HUNDRED;
        Integer materialFeeTotal = orgPriceTotal.multiply(materialFeePercent).intValue() / 100 * 100;
        Integer artFeeTotal = totalPrice - materialFeeTotal;

        itemPriceDRO.setTotalPrice(totalPrice);
        itemPriceDRO.setTotalMaterialPrice(materialFeeTotal);
        itemPriceDRO.setTotalArtPrice(artFeeTotal);
    }

    @Override
    public void calPriceDetail(BaseTariffGroupItemPriceVo vo, ItemPriceCalDTO calDTO) {
        // 非一口价不计算价格
        if (Objects.equals(vo.getPriceStandard(), GlobalConsts.NO)) {
            logger.info("calPriceDetail非一口价不计算价格", vo.getItemId());
            return;
        }
        // 对渠道id进行判断，是否需要取上级渠道的id
        Integer channelId = channelServiceCategoryBService.getAvailableCategoryChannelId(calDTO.getChannelId());
        calDTO.setChannelId(channelId);
        // (计算故障,服务价)
        // 计算参数，渠道折扣，城市系数，品牌系数，分为内外部不同类型
        ItemPriceDTO dto = getFaultPriceDTO(vo, calDTO);

        // 销售价一口价区分明细,且是明细类型1，需要考虑最小价格
        Integer price = calPrice(dto);
        vo.setPrice(price);
        // 内部价，系数相乘即可
        Integer innerPrice = calInnerPrice(dto);
        vo.setInternalSettlementPrice(innerPrice);

        // 一口价不区分明细或者一口价区分明细但是是明细2的（明细2不存在相应的费用）
        boolean cantCalServiceFee = (Objects.equals(vo.getPriceStandard(), GlobalConsts.YES) && Objects.equals(vo.getPriceSplit(), GlobalConsts.NO)) || (!dto.isCanCalMinPrice());
        if (cantCalServiceFee) {
            vo.setPartPrice(null);
            vo.setArtPrice(null);
            vo.setGuaranteePrice(null);
            vo.setServicePrice(null);
        } else {
            // 配件包干费比例
            BigDecimal partRatioPercent = Objects.isNull(vo.getPartRatio()) ? BigDecimal.ZERO : vo.getPartRatio().divide(new BigDecimal(ProductDict.HUNDRED)).setScale(2, BigDecimal.ROUND_HALF_UP);
            BigDecimal artRatioPercent = Objects.isNull(vo.getArtRatio()) ? BigDecimal.ZERO : vo.getArtRatio().divide(new BigDecimal(ProductDict.HUNDRED)).setScale(2, BigDecimal.ROUND_HALF_UP);
            BigDecimal guaranteeRatioPercent =
                    Objects.isNull(vo.getGuaranteeRatio()) ? BigDecimal.ZERO : vo.getGuaranteeRatio().divide(new BigDecimal(ProductDict.HUNDRED)).setScale(2, BigDecimal.ROUND_HALF_UP);
            // 销售价
            BigDecimal priceBig = new BigDecimal(price);
            // 配件包干费，需要对小数部分进行向下取整
            BigDecimal partPrice = priceBig.multiply(partRatioPercent);
            BigDecimal artPrice = priceBig.multiply(artRatioPercent);
            BigDecimal guaranteePrice = priceBig.multiply(guaranteeRatioPercent);
            Integer partPriceInt = partPrice.intValue() / 100 * 100;
            Integer artPriceInt = artPrice.intValue() / 100 * 100;
            Integer guaranteePriceInt = guaranteePrice.intValue() / 100 * 100;
            vo.setPartPrice(partPriceInt);
            vo.setArtPrice(artPriceInt);
            vo.setGuaranteePrice(guaranteePriceInt);
            Integer servicePrice = priceBig.subtract(new BigDecimal(partPriceInt)).subtract(new BigDecimal(dto.getStaticPrice())).subtract(new BigDecimal(artPriceInt))
                    .subtract(new BigDecimal(guaranteePriceInt)).intValue();
            vo.setServicePrice(servicePrice);
            // 如果是普通故障，同时价格小于150，同时考虑难度系数,同时满足一口价区分明细明细类型1的，修改区分明细为不区分（else中已满足一口价区分明细同时明细类型1）
            if (Objects.equals(FAULT_CATEG_ID_NORMAL, vo.getFaultCategId()) && vo.getPrice() < MIN_PRICE_FEN && dto.isDifficultLimit()) {
                vo.setPriceSplit(GlobalConsts.NO);
            }

        }
        // 一口价区分明细，且是明细二的，计算工艺费等
        boolean isDetailTwo = Objects.equals(vo.getPriceStandard(), GlobalConsts.YES)
                && Objects.equals(vo.getPriceSplit(), GlobalConsts.YES) && Objects.equals(vo.getPriceSplitType(), GlobalConsts.YES);
        if (isDetailTwo) {
            Integer materialFee = vo.getMaterialFee();
            BigDecimal materialFeePercent = new BigDecimal(materialFee).divide(new BigDecimal(ProductDict.HUNDRED)).setScale(2, BigDecimal.ROUND_HALF_UP);
            BigDecimal artFeePercent = BigDecimal.ONE.subtract(materialFeePercent);
            BigDecimal artFeeB = new BigDecimal(vo.getPrice()).multiply(artFeePercent).setScale(0, BigDecimal.ROUND_HALF_UP);
            vo.setArtPriceDetailTwo(artFeeB.intValue());
            vo.setMaterialPrice(new BigDecimal(vo.getPrice()).subtract(artFeeB).intValue());
            vo.setArtRatioDetailTwo(100 - materialFee);
        }
    }

    private ItemPriceDTO getFaultPriceDTO(BaseTariffGroupItemPriceVo vo, ItemPriceCalDTO calDTO) {
        ItemPriceDTO dto = new ItemPriceDTO();
        dto.setPrice(vo.getPrice());
        dto.setInternalSettlementPrice(vo.getInternalSettlementPrice());
        Integer channelId = calDTO.getChannelId();
        Integer cityId = calDTO.getCityId();
        Integer brandId = calDTO.getBrandId();
        Integer difficultId = calDTO.getDifficultId();
        Integer bizType = calDTO.getBizType();

        // 获取系数
        if (NumberUtil.isPositiveInteger(brandId)) {
            Float brandRatio = getBrandRatio(channelId, brandId, vo.getProductId(), bizType, BaseCityPriceTypeEnum.PRICE.getCode());
            Float internalBrandRatio = getBrandRatio(channelId, brandId, vo.getProductId(), bizType, BaseCityPriceTypeEnum.INNERPRICE.getCode());
            dto.setBrandRatio(brandRatio);
            dto.setInternalBrandRatio(internalBrandRatio);
        }

        // 系数定价需要考虑品牌系数，折扣，城市系数，城市定价只考虑品牌系数
        if (Objects.equals(vo.getPriceType(), ProductDict.TRIFF_PRICE_TYPE_RATIO)) {
            // 渠道折扣
            if (NumberUtil.isPositiveInteger(channelId)) {
                Float channelDiscont = getChannelDiscount(channelId, bizType, BaseCityPriceTypeEnum.PRICE.getCode());
                Float internalChannelDiscont = getChannelDiscount(channelId, bizType, BaseCityPriceTypeEnum.INNERPRICE.getCode());
                dto.setChannelDiscont(channelDiscont);
                dto.setInternalChannelDiscont(internalChannelDiscont);
            }

            // 城市系数
            if (NumberUtil.isPositiveInteger(cityId)) {
                Float cityRatio = getCityRatio(channelId, cityId, vo.getProductId(), bizType, BaseCityPriceTypeEnum.PRICE.getCode());
                Float internalCityRatio = getCityRatio(channelId, cityId, vo.getProductId(), bizType, BaseCityPriceTypeEnum.INNERPRICE.getCode());
                dto.setCityRatio(cityRatio);
                dto.setInternalCityRatio(internalCityRatio);
            }

        }

        // 难度系数只应用于普通故障和特殊故障
         if (NumberUtil.isNotNullOrZero(difficultId) && DIFFICULT_LIST.contains(vo.getFaultCategId())) {
            DifficultRatio ratio = getDifficultRatio(difficultId);
            if (NumberUtil.isNotNullOrZero(ratio.getDifficultId())) {
                dto.setDifficultRatio(ratio.getRatio());
                dto.setEffectInnerPrice(ratio.getEffectInnerPrice());
                dto.setDifficultLimit(true);
            }
        }

        dto.setStaticPrice((NumberUtil.isNullOrZero(vo.getHourFee()) ? 0 : vo.getHourFee()) + (NumberUtil.isNullOrZero(vo.getTrafficFee()) ? 0 : vo.getTrafficFee())
                + (NumberUtil.isNullOrZero(vo.getCheckFee()) ? 0 : vo.getCheckFee()));

        dto.setPartRatio(vo.getPartRatio());
        dto.setArtRatio(vo.getArtRatio());
        dto.setGuaranteeRatio(vo.getGuaranteeRatio());
        dto.setCityLimit(Objects.equals(vo.getCityLimit(), ProductDict.RADIO_TRUE));
        dto.setBrandLimit(Objects.equals(vo.getBrandLimit(), ProductDict.RADIO_TRUE));
        dto.setItemId(vo.getItemId());
        dto.setProductId(vo.getProductId());
        dto.setTariffId(vo.getTariffId());
        dto.setBizType(bizType);
        dto.setCanCalMinPrice(
                Objects.equals(vo.getPriceStandard(), GlobalConsts.YES) && Objects.equals(vo.getPriceSplit(), GlobalConsts.YES) && Objects.equals(vo.getPriceSplitType(), GlobalConsts.NO));
        dto.setDifficultId(difficultId);
        logger.info("getFaultPriceDTO return:{}", dto);
        return dto;
    }

    private Float getChannelDiscountNoCache(Integer channelId, Integer bizType, Integer priceType) {
        logger.info("getChannelDiscount channelId={},bizType={}", channelId, bizType);
        ChannelCityPriceRatioQuery channelCityPriceRatioQuery = new ChannelCityPriceRatioQuery();
        channelCityPriceRatioQuery.setChannelId(channelId);
        channelCityPriceRatioQuery.setBizType(bizType);
        channelCityPriceRatioQuery.setPriceType(priceType);
        channelCityPriceRatioQuery.setRatioType(ChannelCityRatioTypeEnum.DISCOUNTRATIO.getCode());

        ChannelCityPriceRatio channelCityPriceRatio = channelCityPriceRatioService.findByChannelIdAndCityAndCategAndType(channelCityPriceRatioQuery);
        Float channelDisconut = CACHE_DEFAULT_RATIO;
        if (Objects.isNull(channelCityPriceRatio)) {
            logger.info("getChannelDiscount channelCityPriceRatio is null,return -1f");
            return channelDisconut;
        }

        Double ratio = channelCityPriceRatio.getRatio();
        if (CityPriceUtil.isPositive(ratio)) {
            channelDisconut = new BigDecimal(ratio).floatValue();
        }

        logger.info("getChannelDiscount channelDisconut = {}", channelDisconut);
        return channelDisconut;
    }

    private Float getCityRatioNoCache(Integer channelId, Integer cityId, Integer productId, Integer bizType, Integer cityPriceType) {
        // 查询城市系数
        Float ratio = channelCityPriceRatioBService.findRatioByChannelIdAndCityId(channelId, cityId, productId, bizType, cityPriceType);
        logger.info("getCityRatio ratio = {},channelId={},keepType={},cityId={}，productId={}", ratio, channelId, bizType, cityId, productId);
        return CityPriceUtil.isPositive(ratio) ? ratio : CACHE_DEFAULT_RATIO;
    }

    private Float getBrandRatioNoCache(Integer channelId, Integer brandId, Integer productId, Integer bizType, Integer brandPriceType) {
        logger.info("getBrandRatio params is {},{},{}", brandId, productId, bizType);
        if (!NumberUtil.isPositiveInteger(brandId) || !NumberUtil.isPositiveInteger(productId)) {
            logger.info("getBrandRatio brandId or showProductId为空");
            return CACHE_DEFAULT_RATIO;
        }

        // 先考虑渠道品牌系数，渠道不存在，考虑基础数据品牌
        ServProduct product = servProductService.findByKey(productId);
        ChannelBrandAllLevelRatioQuery channelBrandAllLevelRatioQuery = new ChannelBrandAllLevelRatioQuery();
        channelBrandAllLevelRatioQuery.setChannelId(channelId);
        channelBrandAllLevelRatioQuery.setBrandId(brandId);
        channelBrandAllLevelRatioQuery.setPriceType(brandPriceType);
        channelBrandAllLevelRatioQuery.setBizType(bizType);
        channelBrandAllLevelRatioQuery.setServCategId(product.getServCategId());
        channelBrandAllLevelRatioQuery.setCategOneId(product.getCategOneId());
        channelBrandAllLevelRatioQuery.setCategId(product.getCategId());
        ChannelBrandRatioAllLevelVo vo = channelBrandRatioService.findAllLevelRatio(channelBrandAllLevelRatioQuery);
        if (Objects.isNull(vo)) {
            BrandFactorDRO brandFactorDRO = brandRatioBService.getByBrandIdAndProductIdAndBizTypeAndPriceType(brandId, productId, bizType, brandPriceType);
            logger.info("getBrandRatioNoCache brandFactorDRO = {}", brandFactorDRO);
            if (Objects.isNull(brandFactorDRO) || !CityPriceUtil.isPositive(brandFactorDRO.getRatio())) {
                logger.info("brandFactorDRO  or radio为空");
                return CACHE_DEFAULT_RATIO;
            }
            return new BigDecimal(brandFactorDRO.getRatio()).floatValue();
        }

        Double aDouble = Optional.ofNullable(vo.getCategTwoRatio()).orElse(Optional.ofNullable(vo.getCategOneRatio()).orElse(vo.getBrandRatio()));
        return CityPriceUtil.isPositive(aDouble) ? new BigDecimal(aDouble).floatValue() : CACHE_DEFAULT_RATIO;
    }

    private DifficultRatio getDifficultRatio(Integer difficultId) {
        try {
            return difficultCache.get(difficultId, () -> {
                DifficultRatio ratio = difficultRatioService.findByKey(difficultId);
                if (Objects.isNull(ratio)) {
                    return new DifficultRatio();
                }
                return ratio;
            });
        } catch (Exception e) {
            logger.error("缓存方式获取难度系数失败", e);
            throw new PlatException("缓存方式获取难度系数失败");
        }
    }

    /**
     * 功能描述 ：计算销售价格：每一次的系数计算不能小于不变的部分
     *
     * @param faultPriceDTO：费用计算DTO
     * @return java.lang.Integer
     * @author tanbiao
     * @modifier
     * @since 2019/12/13
     */
    private Integer calPrice(ItemPriceDTO faultPriceDTO) {
        logger.info("calPrice params is {}", faultPriceDTO);
        Integer price = faultPriceDTO.getPrice();
        Float channelDiscont = faultPriceDTO.getChannelDiscont();
        Float cityRatio = faultPriceDTO.getCityRatio();
        Float brandRatio = faultPriceDTO.getBrandRatio();
        BigDecimal difficultRatio = faultPriceDTO.getDifficultRatio();
        boolean cityLimit = faultPriceDTO.isCityLimit();
        boolean brandLimit = faultPriceDTO.isBrandLimit();
        boolean difficultLimit = faultPriceDTO.isDifficultLimit();
        // 一口价区分明细且类型为明细类型1的考虑计算最低价格
        boolean isLimitByPrice = faultPriceDTO.isCanCalMinPrice();
        Integer bizType = faultPriceDTO.getBizType();
        if (NumberUtil.isPositiveInteger(price)) {
            // 最低价格
            Integer minPrice = getMinPrice(faultPriceDTO);
            // 渠道折扣
            Integer channelDisCountPrice = CityPriceUtil.calcCityPrice(price, channelDiscont, bizType);
            if (isLimitByPrice && channelDisCountPrice.compareTo(minPrice) < 0) {
                channelDisCountPrice = minPrice;
            }

            logger.info("渠道折扣价格={}", channelDisCountPrice);

            // 计算价格城市价(受城市系数影响的时候计算价格)
            Integer cityPrice = channelDisCountPrice;
            if (cityLimit) {
                cityPrice = CityPriceUtil.calcCityPrice(channelDisCountPrice, cityRatio, bizType);
                if (isLimitByPrice && cityPrice.compareTo(minPrice) < 0) {
                    cityPrice = minPrice;
                }

                logger.info("查询城市价格={}", cityPrice);
            }
            // 品牌系数
            Integer brandPrice = cityPrice;
            if (brandLimit) {
                brandPrice = CityPriceUtil.calcCityPrice(cityPrice, brandRatio, bizType);
                if (isLimitByPrice && brandPrice.compareTo(minPrice) < 0) {
                    brandPrice = minPrice;
                }

                logger.info("品牌系数价格={}", brandPrice);
            }
            // 难度系数
            Integer difficultPrice = brandPrice;
            if (difficultLimit) {
                difficultPrice = CityPriceUtil.calcCityPrice(difficultPrice, difficultRatio.floatValue(), bizType);
                if (isLimitByPrice && difficultPrice.compareTo(minPrice) < 0) {
                    difficultPrice = minPrice;
                }

                logger.info("品牌系数价格={}", brandPrice);
            }
            price = difficultPrice;
        }

        logger.info("最终价格={}", price);

        return price;
    }

    // 计算内部价
    private Integer calInnerPrice(ItemPriceDTO faultPriceDTO) {
        logger.info("calInnerPrice params is {}", faultPriceDTO);
        Integer price = faultPriceDTO.getInternalSettlementPrice();
        Float channelDiscont = faultPriceDTO.getInternalChannelDiscont();
        Float cityRatio = faultPriceDTO.getInternalCityRatio();
        Float brandRatio = faultPriceDTO.getInternalBrandRatio();
        Float difficultRatio = Objects.isNull(faultPriceDTO.getDifficultRatio()) ? 0f : faultPriceDTO.getDifficultRatio().floatValue();
        boolean cityLimit = faultPriceDTO.isCityLimit();
        boolean brandLimit = faultPriceDTO.isBrandLimit();
        boolean difficultLimit = Objects.equals(faultPriceDTO.getEffectInnerPrice(), GlobalConsts.YES);
        Integer bizType = faultPriceDTO.getBizType();
        if (NumberUtil.isPositiveInteger(price)) {
            price = CityPriceUtil.calcCityPrice(price, channelDiscont, bizType);
            if (cityLimit) {
                price = CityPriceUtil.calcCityPrice(price, cityRatio, bizType);
                logger.info("内部价城市系数价格={}", price);
            }
            if (brandLimit) {
                price = CityPriceUtil.calcCityPrice(price, brandRatio, bizType);
                logger.info("内部价品牌系数价格={}", price);
            }
            if (difficultLimit) {
                price = CityPriceUtil.calcCityPrice(price, difficultRatio, bizType);
                logger.info("内部价难度系数价格={}", price);
            }
        }
        return price;
    }

    /**
     * 功能描述 :最低价格实际上就是技术服务费为0(技术服务费=总价-交通费工时费-总价*配件包干费比例) 遵循689规则
     *
     * @param faultPriceDTO
     * @return java.math.BigDecimal
     * @author tanbiao
     * @modifier
     * @since 2019/12/17
     */
    private Integer getMinPrice(ItemPriceDTO faultPriceDTO) {

        logger.info("faultPriceDTO:{}", faultPriceDTO);
        if (!faultPriceDTO.isCanCalMinPrice()) {
            logger.info("只有一口价区分明细且是明细类型1的才计算最低价格");
            return faultPriceDTO.getPrice();
        }
        Integer staticPrice = faultPriceDTO.getStaticPrice();
        BigDecimal partRatio = Objects.isNull(faultPriceDTO.getPartRatio()) ? BigDecimal.ZERO : faultPriceDTO.getPartRatio();
        BigDecimal artRatio = Objects.isNull(faultPriceDTO.getArtRatio()) ? BigDecimal.ZERO : faultPriceDTO.getArtRatio();
        BigDecimal guaranteeRatio = Objects.isNull(faultPriceDTO.getGuaranteeRatio()) ? BigDecimal.ZERO : faultPriceDTO.getGuaranteeRatio();
        Integer price = faultPriceDTO.getPrice();
        Integer bizType = faultPriceDTO.getBizType();
        // 销售价
        BigDecimal priceBig = new BigDecimal(price);
        // 交通费工时费工艺费
        BigDecimal staticPriceBig = new BigDecimal(staticPrice);
        // 配件包干费比例,不用689
        BigDecimal partRatioPercent = partRatio.divide(new BigDecimal(ProductDict.HUNDRED)).setScale(2, BigDecimal.ROUND_HALF_UP);
        BigDecimal artRatioPercent = artRatio.divide(new BigDecimal(ProductDict.HUNDRED)).setScale(2, BigDecimal.ROUND_HALF_UP);
        BigDecimal guaranteeRatioPercent = guaranteeRatio.divide(new BigDecimal(ProductDict.HUNDRED)).setScale(2, BigDecimal.ROUND_HALF_UP);
        // 配件包干费
        BigDecimal partPriceBig = priceBig.multiply(partRatioPercent);
        BigDecimal artPriceBig = priceBig.multiply(artRatioPercent);
        BigDecimal guaranteePriceBig = priceBig.multiply(guaranteeRatioPercent);
        logger.info("partPriceBig:{},artPriceBig:{},guaranteePriceBig:{}", partPriceBig,artPriceBig,guaranteePriceBig);
        Integer minPrice = staticPriceBig.add(partPriceBig).add(artPriceBig).add(guaranteePriceBig).intValue();
        Integer finalPrice = CityPriceUtil.calcCityPrice(minPrice, RESULT_RATIO, bizType);
        logger.info("getMinPrice return minPrice:{}, 产品id：{}", finalPrice, faultPriceDTO.getProductId());
        // 最低销售价进行689操作
        return finalPrice;
    }

}
